
				By now you will probably know how
	to start a verticalblanking interrupt. Here's how to do it.

		In $6c.L is the address where the computer will jump to 
	each time the Vblank occurs. If you want to put your own routine
	(like a replay routine) in the Vblank interrupt, you just take the
	address in $6c, and save it somewhere (to jump back to when your 
	routine is ready) and put the startaddress of your own routine in it.

..		...
		MOVE.L	$6C,OLDINT+2		; SAVE JUMP-BACK ADDRESS
		MOVE.L	#INT,$6C		; OUR OWN ROUTINE
		...


	INT:	....
		....
	OLDINT:	JMP	$00000000		; OLDINT= 'JMP'-OPCODE
						; OLDINT+2 = JUMPBACK ADDR.

		There are addresses for all interrupts (like $6c). On the
	'!' page I sent last time are other addresses too. Now I have only
	used the Vblank and the Keyboardinterrupt. (this is $68) It occurs
	when you press a key AND when you release it again. Interpreting 
	a pressed key is somewhat difficult. The code for the pressed key
	is found in $bfec01, but first you got to do some operations on it.
	Here's the routine:

..	KEYINT:	CLR.L	D0
		MOVE.B	$BFEC01,D0
		NOT.B	D0
		ROR.B	#1,D0			; bit 8 is up/donw code
	1)	ANDI.W	#$007F,D0		; NOW, D0 = RAW KEYCODE
		....
	OLDKEYINT:
		JMP	$0000000		; install as vblankint

	The code you get in D0 after these operations is what is called
	the RAW keycode. It's NOT an ascii value or something. Somewhere
	in the pack you'll find a table with these codes. As you'll see,
	ALL keys have a value, even the SHIFT and CTRL-keys.
	The line with '1)' kills the leftmost bit in D0.B, this bit is 0 if
	the key is currently PRESSED and 1 if it is RELEASED. To get the
	code in the table you have to compare only the other bits, so in line
	1) this bit is killed. To know if the key is pressed or released, you
	have to check bit 8 before this line. It could be important to check
	because when you perform a printroutine each time you get a keyboard
	interrupt, you will get each pressed key 2 times on the screen (once
	when you press, once when you release)
	

	LIBRARIES
	---------

	Now let's talk a bit about libraries and library-routines. You sure
	have heard that there are several interesting (and less interesting)
	routines stored in the libraries. Most important libraries are in
	ROM, others are on disk (in the libraries directory)  To use routs
	of a lib, you must first open this library, in other words, you must
	get to know where the library is in memory (relative addressing, 
	remember ?)  If the lib is not in memory, it will be loaded from disk
	when you open it. There is a routine which is called 'OPENLIB', and
	it gives you the starting address of the library you opened. Other
	routines are located at a fixed place, relative to this starting
	address. You got some lists of the (standard) libraries from AmigaDos
	There are other libraries, like Explode Library, but they are not
	'offcial' libraries, and I don't have lists of the routines in them.
	If you want, you can create your own libraries, but you'll have to
	find out yourself. Maybe you can learn me when you did. Anyway, let's
	go on. Most routines have some parameters. If you know something 
	about C-language, it could be very simple to understand:

	  result = function([parameter][...])

	General rule: only 1 result ! In Machinecode, this result is Always
	stored in register D0.  The parameters differ from routine to rout.
	See lists in previous sending. For example: the routine OPEN in 
	the dos-library.  you'll find:

		-$001e  -30   Open (name, accessmode)(d1,d2)

	Which means, routine OPEN is at ofset -$001e (or -30 decimal) in the
	doslib, and parameters are NAME in D1, and accessmode in D2. The
	result is in D0. 
	As said, opening a library in fact means getting the startaddress.
	When you know that the function 'Openlib' is in a library itself,
	you could ask the question : how would you open THIS library ?
	 GOOD QUESTION !  The answer is: You Don't Have to !! The startaddr
	of this library is known, you can find it in $4.  (MOVE.L $4,A6
	will put the startaddress of the exec.library in A6, remember: it's
	the CONTENTS of $4 and not $4 that is the startaddress !)
	Once you got this address, you can call any routine in this library,
	among which is OpenLib, so now you can open the other libraries, like
	for example the doslib.
	Here's a complete source of how to open the Dos-library:

..	opendoslib:
		move.l	$4.w,a6			; load execbase
		lea.l	dosname,a1		; parameter for openlib
		jsr	-408(a6)		; execute routine openlib
		move.l	d0,dosbase		; store result
		tst.l	d0			; something wrong ?
		beq	error			; yep !
		rts				; nope !

	error:	....				; HELP, something wrong !

	dosname:	dc.b	"dos.library",0
			even
	dosbase:	dc.l	0

	As said, D0 is the result of the operation. In most cases, if D0 is
	zero (tst.l d0), there was something wrong, like the library couldn't
	be opened, etc.  However, when you can't open Doslib, not much can be
	done I'm afraid, and it won't happen anyway, so you don't have to
	check this really. But when you open a dozen of windows, it could 
	happen that you run out of memory, and a D0=0 would tell you so.
	After your source is ready to RTS to CLI, you should always close
	opened libraries (except the EXEC, which in fact you didn't open)
	This is done as follows:

..	Closedoslib:
		move.l	$4.w,a6			; load execbase
		move.l	dosbase,a1		; start of lib to close
		jsr	-414(a6)		; close it

	2 notes on this:  move.l dosbase,a1     IS NOT THE SAME AS 
			  lea.l  dosbase,a1  !!!
	You really need the VALUE IN dosbase and not the address #dosbase.
	(I say this coz I made this mistake often)
	2nd note:  MOVE.L  $4.W,a6    notice the $4.W : this saves you 2
	bytes: address $4 is in the lowest 64K of memory, and so it can be
	addressed using only 1 word instead of 1 longword. 
	move.l	$4,a6   is assembled something like this:  3245 00000004
	move.l  $4.w,a6 	"	"	"	:  3265 0004
	WOW AIN'T THAT SHOCKING !! WE SAVED 2 BYTES !!
	(and we wasted only 7 lines)

	Now here's some detailed descriptions of the parameters for the 
	most commonly used DOSLIB routines, I can't tell'em all, 1) coz I
	haven't used them yet and I dunno, 2) coz there are too much of'em
	3) coz I haven't got all day 4) coz you won't be using them neither.

	One very interesting routine is the EXECUTE. It makes it possible to
	run any file on disk (like a demo) straight from an assembler program
	(like a MENU or a LOADER...) Here's the routine, (ofcourse after
	opening the DOSLIB)


..	EXECUTE_IT:
		...
		move.l	dosbase,a6		; load dosbase
		move.l	#command,d1		; pointer to command in d1
		clr.l	d2
		clr.l	d3
		jsr	-222(a6)		; execute
		move.l	d0,returncode		; optional, not often used
		...

	command:	dc.b	"df0:demo1",0	; filename to execute
			even

	d2 and d3 are used to redirect input and output (just set to zero
	if you don't use them)  (like  "dir df0: > dirfile",  d2 would be
	a pointer to "DIRFILE")
	When you wish to use 'execute' routine, the command RUN should be in
	the C: directory. If RUN isn't there, nothing will be executed...
	The result of the excute is a returncode, which the finished program
	gives back in d0. (You sometimes see badly written demos giving a
	returncode = xxxxx  when they're finished, so now you know why: they
	forgot to clear D0 at the end. (This is only noticable when they're
	run from within a batchfile))  In advanced DOS-scripts, this is used
	to give results (like 'file not found') to other doscommands.

..	OPEN_FILE:
		...
		move.l	dosbase,a6		; load dosbase
		move.l	#filename,d1		; ptr to filename
		move.l	#1005,d2		; mode = read
		jsr	-30(a6)			; open
		move.l	d0,handle		; save result
		...

	filename:	dc.b	"df0:boringfile",0
			even
	handle:		dc.l	0

	You can open a file in 3 ways:  read from it: mode = 1005
	write to it: mode = 1006, and read/write: mode = 1004
	in D0 you get the handle to that file, you need it for further 
	operations.

..	READING A FILE

	the description for this routine is:

	amount = Read (handle, buffer, length)
	  d0   =  -42    d1      d2      d3

	(This is a somewhat shorter notation, I'll use this in the next 
	examples. One last time, I'll give you the source for this)

		...
		move.l	dosbase,a6
		move.l	handle,d1		; d1 = handle (value)
		move.l	#buffer,d2		; d2 = buffer (pointer to)
		move.l	#length,d3		; d3 = length (value)
		jsr	-42(a6)			; Read
		move.l	d0,....			; optional

	handle:		dc.l	0		; filled by 'lock'
	length=		xxxxx
	buffer:		blk.b	length,0
			even

	You can read more than one time, in fact you can read until you
	reach the end of the file.
	d0 is the amount of bytes read (amount <= length)
	d0 = 0 :  end of file reached
	d0 = -1 : error (disk removed or something, I suppose)

..	WRITING A FILE

	amount = Write (handle, buffer, length)
	 d0       -48    d1       d2      d3

	same param's as in read

..	SEEK

	move the file-pointer in a opened file

	Position = SEEK (handle, distance, mode)
	   d0       -66    d1       d2      d3

	mode tells whether the distance is measured starting at the start
	of the file (mode = -1), or from the current position (mode = 0)
	or starting at the end (mode = 1)
	Distance then tells the offset from the defined position:
	Distance -20 with mode 1 puts the filepointer to 20 bytes from the
	end of the file etc.

..	IOERR

	get the precise dos-error

	error = IOERR ()
	 d0       -132

	Refer to DOS-manual for errorvalues & meanings: example

		121: not executable ('file is not an object module')
		221: disk full
		...


	OK, so much for the most important dos-routines.  Maybe you'll use
	some of these in a menu or a bootloader or something.
	As I know out of experience, it's best not to mess around with the
	interrupts/DMA when using DOS routines, coz there's much chance that
	it won't work/crash once in a while. 
	The Readdir routine which is desacribed now, is causing me LOADS of
	trouble, it just won't work when I want it, and the weird thig is that
	it works sometimes. I HATE THAT ! I have to cancel all my current
	projects coz they all need these silly diskactivities and they just
	don't work together with my hardware-routines. (I told you before)


		....
		move.l	dosbase(pc),a6
		move.l	#path,d1		; name of directory
		moveq.l	#-2,d2			; read
		jsr	-84(a6)			; 'lock'
		tst.l	d0
		beq.s	dir_error
		move.l	d0,lock

		move.l	lock(pc),d1
		move.l	#fileinfo,d2		; ptr to fileinfo block
		jsr	-102(a6)		; 'examine'
		tst.l	d0			;    fills up fileinfo with
		beq.s	dir_error		;    info about the directory 
	
	dir_loop:
		move.l	lock(pc),d1
		move.l	#fileinfo,d2
		jsr	-108(a6)		; 'examine next'
		tst.l	d0			;    fills up fileinfo with
		beq	dir_error		;    info about files/subdirs
		bsr	dir_printnames		; routine to print name
		bra.s	dir_loop		; next, until d0 = 0
	dir_error:
		jsr	-132(a6)		; IOERR check which error
		rts
	
	path:		dc.b	"df0:",0
			even
	lock:		dc.l	0
	fileinfo:	blk.b	260,0


	The routines 'examine' and 'exnext' will fill up a block of data
	(fileinfo) which has the following structure:

	offset:	0	drivenumber
		4	type of entry (dir/file)
		8	filename (108 bytes)
		116	protection code
		120	type of entry
		124	size of file (bytes)
		128	number of blocks
		132	days	\
		136	minutes	 |  creation time
		140	ticks	/
		144	comment (116 bytes filenote)
		260

	As I said, I've still got major problems with this thing, and I
	haven't been able to test all of it. For example I think that the
	name of a directory starts at ofset 10 instead of ofset 8, but I'm
	not sure. This book I got isn't complete by a 100 lightyears !
	Above all, in the whole book are several 'typing errors' as it is
	translated from German. Ow boy.

	Anyway, now we've seen nearly all of the DOS-things, it's time to
	go to a lower level: the TRACKDISK device. Devices are something
	between hardware and library-programming. There are several devices,
	like 'trackdisk', 'printer', 'console',...
	They use more 'sophisticated' stuff like nodes and messages to 
	communicate between other tasks, and it's this stuff that I'm trying
	to master now (but it's not working yet) Anyway, I've done some
	experiments with trackdisk already. here's an attempt:

	doio:	move.l	$4.w,a6			;
		sub.l	a1,a1			; 
		jsr	-294(a6)		; findtask (buerk)
		move.l	d0,readreply+$10	; 
		lea.l	readreply,a1		; 
		jsr	-354(a6)		; addport (buerk)
		lea.l	diskio,a1		;
 		move.l	#0,d0			; drive:  df0:
		clr.l	d1			; no flags (?)
		lea.l	devicename,a0		;
		jsr	-444(a6)		; opendevice !!
		tst.l	d0
		bne.s	trerror

		lea.l	diskio,a1
		move.l	#readreply,14(a1)	; reply port (buerk)
		move.w	#2,28(a1)		; instruction : read
		move.l	#diskbuff,40(a1)	; ptr to buffer
		move.l	#.....,36(a1)		; amount of bytes to read
		move.l	#.....,44(a1)		; ofset on disk
		jsr	-456(a6)		; do-I/O
	
		lea.l	diskio,a1
		move.w	#9,28(a1)
		move.l	#0,36(a1)
		jsr	-456(a6)		;motorout
		lea.l	readreply,a1
		jsr	-360(a6)		;remport (buerk)
		lea.l	diskio,a1
		jsr	-450(a6)		;closedev
	trerror:rts
	
	diskio:		blk.l	20,0
	readreply:	blk.l	8,0
	devicename:	dc.b	"trackdisk.device",0
			even
	diskerror:	dc.b	0
			even
	diskbuff:	dc.l	0


	The routines with 'Buerk' are not really clear to me. They refer to
	a structure that is used by the device, it looks like this:

	ofset:	0	...		; typical node structure,
					; don't bother
		14	pointer to replyport (task communication)
		18	length of structure (don't bother)

		20	pointer to devicenode (don't bother)
		24	unit (don't bother) (?)
		28	command:  These are (some of) the possible commands
			for the devices:
				read:		#2
				write:		#3
				update:		#4 (?)
				clear:		#5 (?)
				motorout:	#9 (only for trackdisk)
		30	flags (don't bother) (?)
		31	error (example: 28 = write prot)
			 (didn't work when I tried or I did smth wrong)
		32	actual number of read/written bytes
		36	number of bytes to send/recieve
			example:    number = 2*512:  2 blocks to transfer
		40	ptr to memory
		44	offset (amount of bytes behind 1st byte on disk)
			example: offset = 880*512:  read/write at block 880
				 there are 22 blocks/track

	Maybe it's now the right time to tell you the relation between the
	different 'levels' of ROM-routines in the AMiga. At the highest
	level you have the DOS-routines, like read, write, execute. As you
	can imagine, there's a whole lot of programming behind these commands
	as they handle trackread, updating of directory, detecting of errors
	directory/file handling, checksums, free space etc.  The next level 
	is the TRACKDISK. Dos-routines use the trackdisk-device, this is not
	as sophisticated as DOS, as it only reads/writes tracks, there's 
	nothing like file/directory/checksums at this level. It's therefor a
	whole bit faster. (especially coz you can reduce the read/write-head
	movement to a minimum by putting programs on consecutive tracks.
	Most megademos use trackdisk, you can recognise it by a 'tack-tack-
	tack' with constant speed. The lowest level is the DMA, like we did
	when using blitter, for example. You can just as well put values in
	special registers used for diskdrive, and get some things read 
	from disk. This is the most complicated way of working, and also 
	the fastest.Working this way you can chenge the speed of the drive-
	head (and make the funny noise you sometimes with some hardware 
	loader (njiiii-njiiii-retetetete / ow boy it's melting !!)
	I've heard that you can kill your drive by messing too much with the
	drive-hardware registers, but anyway, sounds fascinating. You can also
	read tracks behind 79 with the hardware-method, which could make head
	trying to read on the plastic of your disks. (aaargh)
	These same 3 levels can be found in other parts of the amiga, but 
	coz of a lack of decent documentation, I haven't been able to 
	experiment on them. Until then we will go on messing with the
	hardware and the DMA.


	NOW. I guess you know most thing you need to know now, for more
	detailled things you can now refer to manual, (most manuals forget
	that there are beginners too in this world, they just are too 
	difficult to start with)
